﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using caedisi.Web.Services;
using caedisi.Web.DataModel;
using System.ServiceModel.DomainServices.Client;
using System.Linq;

namespace caedisi.Controller
{

    
    /// <summary>
    /// the controller object of the cellular automata
    /// </summary>
    public class CellularAutomataController
    {
        private static object syncRoot = new Object();

        private CellularAutomataDomainContext _context;
        /// <summary>
        /// Gets the context.
        /// </summary>
        public CellularAutomataDomainContext Context
        {
            get { return _context; }
        }
       
        private static volatile CellularAutomataController instance;
        /// <summary>
        /// Gets the instance.
        /// </summary>
        public static CellularAutomataController Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new CellularAutomataController();
                    }
                }
                return instance;
            }
        }
               

        /// <summary>
        /// Initializes a new instance of the <see cref="CellularAutomataController"/> class.
        /// </summary>
        public CellularAutomataController()
        {
            _context = new CellularAutomataDomainContext();
        }

        private CellularAutomata _CurrentEntity;
        /// <summary>
        /// Gets or sets the current entity.
        /// </summary>
        /// <value>
        /// The current entity.
        /// </value>
        public CellularAutomata CurrentEntity
        {
            get
            {
                return _CurrentEntity;
            }
            set
            {
                if (value == null)
                    _context.CellularAutomatas.Detach(_CurrentEntity);
                else
                {
                    ClearAllLoadedObjects();
                    _context.CellularAutomatas.Add(value);
                }
                _CurrentEntity = value;
            }
        }

        #region Cellular Automata
        /// <summary>
        /// Loads the specified cellular automata id.
        /// </summary>
        /// <param name="cellularAutomataId">The cellular automata id.</param>
        /// <param name="LoadCompleted">The load completed.</param>
        public void Load(int cellularAutomataId, Action<CellularAutomata> LoadCompleted)
        {
            ClearAllLoadedObjects();

            EntityQuery<CellularAutomata> query = _context.GetCellularAutomataWithChildrenQuery().Where(CA => CA.CellularAutomataId == cellularAutomataId);

            //clearing previous results stored inside the domain context
            _context.Load(
                query,
                loadOperation =>
                {
                    if (!loadOperation.HasError
                        && _context.CellularAutomatas != null
                        && _context.CellularAutomatas.Count > 0)
                    {
                        _CurrentEntity = _context.CellularAutomatas.First();  //_dataEntryContext.LocalUnions should always return a single entity                         
                    }


                    LoadCompleted(_CurrentEntity);
                },
                null
            );
        }



        public CellularAutomata LoadCellularAutomata(int cellularAutomataId)
        {

            EntityQuery<CellularAutomata> query = _context.GetCellularAutomatasQuery().Where(CA => CA.CellularAutomataId == cellularAutomataId);
            LoadOperation<CellularAutomata> loadOp = this._context.Load(query);
            loadOp.Entities.Count();
            return loadOp.Entities.ElementAt(0);
        }




        /// <summary>
        /// Lazies the load all cellular automata.
        /// </summary>
        /// <param name="LoadCompleted">The load completed.</param>
        public void LazyLoadAllCellularAutomata(Action<EntitySet<CellularAutomata>> LoadCompleted)
        {
            EntityQuery<CellularAutomata> query = _context.GetCellularAutomatasQuery();

            _context.Load(
               query,
               loadOperation =>
               {                  
                   if (loadOperation.HasError)
                   {
                       ;//TODO
                   }
                   LoadCompleted(_context.CellularAutomatas);
               },
               null);
        }


        /// <summary>
        /// Removes the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public void Remove(CellularAutomata entity)
        {
            throw new NotImplementedException();
        }
        
        #endregion

        #region TransitionRule

        /// <summary>
        /// Removes the transition rule.
        /// </summary>
        /// <param name="transitionRule">The transition rule.</param>
        public void RemoveTransitionRule(TransitionRule transitionRule, CellularAutomata cellular)
        {
            try
            {
                foreach (NeighbourhoodStateConfiguration neighbourStateConfiguration in transitionRule.NeighbourhoodStateConfigurations)
                {
                    transitionRule.NeighbourhoodStateConfigurations.Remove(neighbourStateConfiguration);
                    this.Context.NeighbourhoodStateConfigurations.Remove(neighbourStateConfiguration);
                }

                this.CurrentEntity.TransitionRules.Remove(transitionRule);
                this.Context.TransitionRules.Remove(transitionRule);
            }
            catch (Exception)
            {
                cellular.TransitionRules.Remove(transitionRule);
            }
        }

        #endregion

        /// <summary>
        /// Saves the specified save completed.
        /// </summary>
        /// <param name="SaveCompleted">The save completed.</param>
        public void Save(Action<bool, Exception> SaveCompleted)
        {
            _context.SubmitChanges(
                  submitOperation =>
                  {
                      if (submitOperation.HasError)
                      {
                          ;
                      }
                      SaveCompleted(!submitOperation.HasError, submitOperation.Error);
                  },
                  null);
        }

        /// <summary>
        /// Gets a value indicating whether this instance has changes.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance has changes; otherwise, <c>false</c>.
        /// </value>
        public bool HasChanges
        {
            get { return (_context != null ? _context.HasChanges : false); }
        }

        /// <summary>
        /// Rejects the changes.
        /// </summary>
        public void RejectChanges()
        {
            this._context.RejectChanges();
        }

        #region private methods

        /// <summary>
        /// Clears all loaded objects.
        /// </summary>
        private void ClearAllLoadedObjects()
        {
            _context.CellularAutomatas.Clear();
            _CurrentEntity = null;
        }

        #endregion


    }
}
